package com.kun.util.excel;

import com.xiaoleilu.hutool.lang.Assert;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class ExcelUtil {

    private static Map classCache = new HashMap();

    public static void exportExcel(Class clazz, List data, OutputStream outputStream) throws Exception {

        Assert.notNull(data);

        //解析出被注解的字段
        Map<String, ExcelColumn> annotationMap = parsingAnnotation(clazz);

        //导出数据
        exportData(data, outputStream, annotationMap);

    }

    private static void exportData(List data, OutputStream outputStream, Map<String, ExcelColumn> annotationMap) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, IOException {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        Sheet sheet = workbook.createSheet();

        //创建第一行标题
        createTitle(sheet, annotationMap);

        Object[] keys = annotationMap.keySet().toArray();

        for (int j = 0; j < data.size(); j++) {
            Class clazz = data.get(j).getClass();

            Row row = sheet.createRow(j + 1);

            for (int i = 0; i < keys.length; i++) {
                Method method = clazz.getMethod("get" + firstToUpperCase(keys[i].toString()));
                Object value = method.invoke(data.get(j));
                Class typeHandleClass = annotationMap.get(keys[i]).typeHandle();
                if (typeHandleClass != DefaultExcelTypeHandle.class) {
                    Method typeConversion = typeHandleClass.getMethod("dataProcessing", Object.class);
                    value = typeConversion.invoke(getTypeHandleObj(typeHandleClass), value);
                }
                if (value != null) {
                    row.createCell(i).setCellValue(value.toString());
                }
            }
        }

        writeExcel(workbook, outputStream);

    }

    private static Object getTypeHandleObj(Class typeHandleClass) throws IllegalAccessException, InstantiationException {
        Object obj = classCache.get(typeHandleClass);
        if (obj == null) {
            obj = typeHandleClass.newInstance();
            classCache.put(typeHandleClass, obj);
        }
        return obj;
    }

    private static void writeExcel(SXSSFWorkbook workbook, OutputStream outputStream) throws IOException {
        workbook.write(outputStream);
        workbook.dispose();
        workbook.close();
    }

    private static void createTitle(Sheet sheet, Map<String, ExcelColumn> annotationMap) {
        Row row = sheet.createRow(0);
        Object[] keys = annotationMap.keySet().toArray();
        for (int i = 0; i < keys.length; i++) {
            row.createCell(i).setCellValue(annotationMap.get(keys[i]).value());
        }
    }

    /**
     * 首字母转为大写
     *
     * @param str
     * @return
     */
    private static String firstToUpperCase(String str) {
        char[] chars = str.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] = (char) (chars[0] - 32);
        }
        return new String(chars);
    }

    private static Map<String, ExcelColumn> parsingAnnotation(Class clazz) {
        Map<String, ExcelColumn> annotationMap = new LinkedHashMap<>();
        //获取所有的字段
        Field[] fields = clazz.getDeclaredFields();
        List<Field> fieldList = new ArrayList<>();
        for (Field field : fields) {
            ExcelColumn excelColumn = field.getAnnotation(ExcelColumn.class);
            if (excelColumn != null) {
                fieldList.add(field);
            }
        }
        fieldList.sort(Comparator.comparing(f -> f.getAnnotation(ExcelColumn.class).order()));
        fieldList.forEach(f -> annotationMap.put(f.getName(), f.getAnnotation(ExcelColumn.class)));
        return annotationMap;
    }

}
